package com.cmc.cloud.cmclink.doc.util;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 文件打包压缩工具
 *
 * @author 集运管理员
 */
@Slf4j
public class ZipCompressor {

    public static final String ZIP = ".zip";

    /**
     * 压缩单个文件到ZIP
     * @param sourceFile 源文件路径
     * @param zipFile 输出的ZIP文件路径
     */
    public static void compressSingleFile(String sourceFile, String zipFile) throws IOException {
        File fileToZip = new File(sourceFile);
        if (!fileToZip.exists()) {
            throw new FileNotFoundException("文件不存在: " + sourceFile);
        }

        try (FileOutputStream fos = new FileOutputStream(zipFile);
             ZipOutputStream zos = new ZipOutputStream(fos);
             FileInputStream fis = new FileInputStream(fileToZip)) {

            ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
            zos.putNextEntry(zipEntry);

            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) >= 0) {
                zos.write(buffer, 0, length);
            }

            zos.closeEntry();
            System.out.println("单个文件压缩完成: " + zipFile);
        }
    }

    /**
     * 压缩多个文件到ZIP
     * @param sourceFiles 源文件路径数组
     * @param zipFile 输出的ZIP文件路径
     */
    public static void compressMultipleFiles(Map<String,byte[]> sourceFiles, String zipFile) {
        try (FileOutputStream fos = new FileOutputStream(zipFile);
             ZipOutputStream zos = new ZipOutputStream(fos)) {
            sourceFiles.forEach((fileName,fileData) ->{
                ZipEntry zipEntry = new ZipEntry(fileName);
                try {
                    zos.putNextEntry(zipEntry);
                    zos.write(fileData);
                    zos.flush();
                    zos.closeEntry();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("多个文件压缩完成: " + zipFile);
            });

        } catch (Exception e) {
            log.error(e.getMessage(),e);
            throw new RuntimeException(e);
        }
    }
    /**
     * 压缩多个文件到ZIP
     * @param sourceFiles 源文件路径数组
     * @param zipFile 输出的ZIP文件路径
     */
    public static void compressMultipleFiles(List<File> sourceFiles, String zipFile) {
        try (FileOutputStream fos = new FileOutputStream(zipFile);
             ZipOutputStream zos = new ZipOutputStream(fos)) {
            for (File file : sourceFiles) {
                if (!file.exists()) {
                    continue;
                }
                try (FileInputStream fis = new FileInputStream(file)) {
                    ZipEntry zipEntry = new ZipEntry(file.getName());
                    zos.putNextEntry(zipEntry);
                    byte[] buffer = new byte[1024];
                    int length;
                    while ((length = fis.read(buffer)) >= 0) {
                        zos.write(buffer, 0, length);
                    }
                    zos.closeEntry();
                } catch (FileNotFoundException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("多个文件压缩完成: " + zipFile);
            }

        } catch (Exception e) {
            log.error(e.getMessage(),e);
            throw new RuntimeException(e);
        }
    }


    /**
     * 压缩多个文件到ZIP
     * @param sourceFiles 源文件路径数组
     * @param zipFile 输出的ZIP文件路径
     */
    public static void compressMultipleFiles(String[] sourceFiles, String zipFile) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(zipFile);
             ZipOutputStream zos = new ZipOutputStream(fos)) {

            for (String sourceFile : sourceFiles) {
                File file = new File(sourceFile);
                if (!file.exists()) {
                    System.err.println("文件不存在，跳过: " + sourceFile);
                    continue;
                }
                try (FileInputStream fis = new FileInputStream(file)) {
                    ZipEntry zipEntry = new ZipEntry(file.getName());
                    zos.putNextEntry(zipEntry);
                    byte[] buffer = new byte[1024];
                    int length;
                    while ((length = fis.read(buffer)) >= 0) {
                        zos.write(buffer, 0, length);
                    }
                    zos.closeEntry();
                }
            }
            System.out.println("多个文件压缩完成: " + zipFile);
        }
    }

    /**
     * 压缩文件夹到ZIP
     * @param sourceDir 源文件夹路径
     * @param zipFile 输出的ZIP文件路径
     * @param keepDirStructure 是否保留目录结构
     */
    public static void compressFolder(String sourceDir, String zipFile, boolean keepDirStructure) throws IOException {
        long start = System.currentTimeMillis();

        try (FileOutputStream fos = new FileOutputStream(zipFile);
             ZipOutputStream zos = new ZipOutputStream(fos)) {

            File sourceFolder = new File(sourceDir);
            if (!sourceFolder.exists()) {
                throw new FileNotFoundException("文件夹不存在: " + sourceDir);
            }

            compressDirectory(sourceFolder, zos, sourceFolder.getName(), keepDirStructure);

            long end = System.currentTimeMillis();
            System.out.println("文件夹压缩完成: " + zipFile + "，耗时: " + (end - start) + " ms");
        }
    }

    /**
     * 递归压缩目录
     */
    private static void compressDirectory(File folder, ZipOutputStream zos,
                                          String parentPath, boolean keepDirStructure) throws IOException {
        File[] files = folder.listFiles();
        if (files == null || files.length == 0) {
            // 空文件夹也创建条目
            if (keepDirStructure) {
                ZipEntry zipEntry = new ZipEntry(parentPath + "/");
                zos.putNextEntry(zipEntry);
                zos.closeEntry();
            }
            return;
        }

        for (File file : files) {
            if (file.isDirectory()) {
                String newParentPath = keepDirStructure ? parentPath + "/" + file.getName() : file.getName();
                compressDirectory(file, zos, newParentPath, keepDirStructure);
            } else {
                try (FileInputStream fis = new FileInputStream(file)) {
                    String entryName = keepDirStructure ? parentPath + "/" + file.getName() : file.getName();

                    ZipEntry zipEntry = new ZipEntry(entryName);
                    zos.putNextEntry(zipEntry);

                    byte[] buffer = new byte[1024];
                    int length;
                    while ((length = fis.read(buffer)) >= 0) {
                        zos.write(buffer, 0, length);
                    }
                    zos.closeEntry();
                }
            }
        }
    }

    /**
     * 获取文件夹中所有文件的列表
     */
    private static List<File> getAllFiles(File folder) {
        List<File> fileList = new ArrayList<>();
        File[] files = folder.listFiles();

        if (files != null) {
            for (File file : files) {
                if (file.isFile()) {
                    fileList.add(file);
                } else if (file.isDirectory()) {
                    fileList.addAll(getAllFiles(file));
                }
            }
        }
        return fileList;
    }

    /**
     * 主方法 - 测试程序
     */
    public static void main(String[] args) {
        try {
            System.out.println("=== Java ZIP压缩工具测试 ===\n");

            // 测试1: 压缩单个文件
            System.out.println("1. 压缩单个文件:");
            compressSingleFile("document.txt", "single_file.zip");

            // 测试2: 压缩多个文件
            System.out.println("\n2. 压缩多个文件:");
            String[] filesToCompress = {"file1.txt", "file2.pdf", "image.jpg"};
            compressMultipleFiles(filesToCompress, "multiple_files.zip");

            // 测试3: 压缩文件夹（保留目录结构）
            System.out.println("\n3. 压缩文件夹（保留目录结构）:");
            compressFolder("my_documents", "folder_with_structure.zip", true);

            // 测试4: 压缩文件夹（所有文件在根目录）
            System.out.println("\n4. 压缩文件夹（所有文件在根目录）:");
            compressFolder("my_documents", "folder_flat.zip", false);

            System.out.println("\n=== 所有测试完成 ===");

        } catch (IOException e) {
            System.err.println("压缩过程中出现错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
}
